package com.gitee.qdbp.jdbc.support;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitee.qdbp.tools.utils.ConvertTools;
import com.gitee.qdbp.tools.utils.PropertyTools;
import com.gitee.qdbp.tools.utils.StringTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

class DataSourceConfig {

    private static final Logger log = LoggerFactory.getLogger(DataSourceConfig.class);

    private final Properties properties;
    private String configString;
    private String dbType;
    private String dbAddress;
    private String dbName;
    private String dbSchema;
    private String userName;
    private byte[] password;

    /** 缓存, 用于首次获取时记录日志的判断依据 **/
    private final Map<String, String> changeCache = new HashMap<>();

    public DataSourceConfig(Properties properties) {
        this.properties = properties;
    }

    public Properties getProperties() {
        return this.properties;
    }

    /**
     * 根据dbtype从配置项中查找配置内容<br>
     * 如key = jdbc.url, suffixes=x.y.z<br>
     * 取值顺序为: jdbc.url.x.y.z - jdbc.url.x.y - jdbc.url.x - jdbc.url
     * 
     * @param key KEY前缀
     * @param replacePlaceholder 是否替换占位符
     * @param throwOnNotFound 未找到配置时是否报错
     * @return 配置内容
     */
    protected String findPropertyUseSuffix(String key, boolean replacePlaceholder, boolean throwOnNotFound) {
        String suffixes = this.dbType;
        char dot = '.';
        List<String> keys = new ArrayList<>();
        keys.add(key + dot + suffixes);
        int index = suffixes.length();
        while (true) {
            index = suffixes.lastIndexOf(dot, index - 1);
            if (index <= 0) {
                break;
            }
            keys.add(key + dot + suffixes.substring(0, index));
        }
        keys.add(key);

        String realKey = null;
        String realValue = null;
        for (String k : keys) {
            String value = PropertyTools.getString(properties, k, false);
            if (value == null) {
                continue;
            } else {
                realKey = k;
                realValue = value;
                break;
            }
        }
        if (realValue != null && realValue.length() > 0) {
            String result = replacePlaceholder ? replacePlaceholder(realValue) : realValue;
            boolean changed = !changeCache.containsKey(key) || !VerifyTools.equals(result, changeCache.get(key));
            if (changed) { // 只有首次获取才输出日志
                changeCache.put(key, result);
                if (log.isDebugEnabled()) {
                    log.debug("Resolved property value: " + realKey + " = " + result);
                }
            }
            return result;
        } else {
            if (!throwOnNotFound) {
                return null;
            }
            String msg;
            if (realValue == null) {
                msg = "Property value not found: " + ConvertTools.joinToString(keys, " or ");
            } else {
                msg = "Property value is blank, key=" + realKey;
            }
            throw new IllegalArgumentException(msg);
        }
    }

    private String replacePlaceholder(String s) {
        if (s == null || s.indexOf('{') < 0 || s.indexOf('}') < 0) {
            return s;
        }
        return StringTools.format(s, "address", dbAddress, "dbname", dbName, "schema", dbSchema);
    }

    public String getConfigString() {
        return configString;
    }

    public void setConfigString(String configString) {
        this.configString = configString;
    }

    public String getDbType() {
        return dbType;
    }

    protected void setDbType(String dbType) {
        this.dbType = dbType;
    }

    public String getDbAddress() {
        return dbAddress;
    }

    protected void setDbAddress(String dbAddress) {
        this.dbAddress = dbAddress;
    }

    public String getDbName() {
        return dbName;
    }

    protected void setDbName(String dbName) {
        this.dbName = dbName;
    }

    public String getDbSchema() {
        return dbSchema;
    }

    protected void setDbSchema(String dbSchema) {
        this.dbSchema = dbSchema;
    }

    public String getUserName() {
        return userName;
    }

    protected void setUserName(String userName) {
        this.userName = userName;
    }

    public byte[] getPassword() {
        return password;
    }

    protected void setPassword(byte[] password) {
        this.password = password;
    }
}
